<?php

declare(strict_types=1);

namespace MultiWorker\Logger;

abstract class Channel
{
    /**
     * channel config.
     *
     * @var array
     */
    protected $config = [];

    /**
     * Channel Cnstructor.
     *
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        $this->config = array_merge($this->config,$config);
    }

    /**
     * 写日志
     *
     * @param string $message
     * @param mixed $level
     * @param array $context
     * @return void
     */
    abstract public function write($message,$level,array $context = []);

    /**
     * 格式化内容
     *
     * @param string $message
     * @param string $level
     * @param array $context
     * @return string
     */
    protected function formatContent ($message,$level,array $context = []): string
    {
        $contextFormat = $this->getConfig('context_format',function ($context) {
            return empty($context) ? '' : json_encode($context,JSON_UNESCAPED_UNICODE);
        });
        $timeFormat    = $this->getConfig('time_format','Y-m-d H:i:s');
        $format        = $this->getConfig('format');
        return $this->parseStringVar((string)$format,[
            'time'    => date($timeFormat,time()),
            'level'   => $level,
            'message' => $message,
            'context' => $contextFormat($context) ?: '',
        ]) . PHP_EOL;
    }

    /**
     * 解析字符串变量
     *
     * @param  string  $string
     * @param  array  $vars
     * @return string
     */
    protected function parseStringVar(string $string, array $vars = [], array $options = ['open' => ':', 'close' => '']): string 
    {
        return preg_replace_callback(sprintf(
            '/%s\s?([\w]+)\s?%s/', preg_quote($options['open']), preg_quote($options['close'])
        ), function ($matchs) use ($vars) {
            return $vars[$matchs[1]] ?? '';
        }, $string);
    }

    /**
     * 获取当前通道的配置内容
     *
     * @param string $key
     * @param mixed $default
     * @return array
     */
    protected function getConfig (string $key,$default = null)
    {
        $name = basename(str_replace('\\','/',static::class));
        $name = strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . '_' . "$2", $name));
        $data = array_merge($this->config,$this->config[$name] ?? []);
        return $data[$key] ?? $default;
    }

    /**
     * is apart level.
     *
     * @param string $level
     * @return boolean
     */
    protected function isApartLevel ($level): bool
    {
        $apartLevel = $this->getConfig('apart_level',true);
        if (empty($apartLevel)) {
            return false;
        }
        if ($apartLevel === true) {
            return true;
        }
        return is_array($apartLevel) && in_array(
            strtoupper($level),array_map('strtoupper',$apartLevel)
        );
    }
}